package handlers

import (
	"GoServer/common"
	"GoServer/entrance/game/game_service"
	"GoServer/entrance/platform/douyin"
	"GoServer/entrance/rank"
	"GoServer/message"
	"GoServer/models"
	"GoServer/net"
	"GoServer/net/ws"
	"GoServer/utils/config"
	"GoServer/utils/databases"
	"GoServer/utils/databases/mongodb"
	"GoServer/utils/debug"
	"GoServer/utils/tool"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.mongodb.org/mongo-driver/bson"
	"io/ioutil"
	"net/http"
	"strconv"
	"sync"
)

// / 获取直播房间id [post]
func RequestLiveRoomID(c *gin.Context) {
	token := c.PostForm("token")

	fmt.Println("客户端请求的token:", token)
	if token == "" {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "token 参数错误, 请重新启动玩法")
		return
	}

	result, err := douyin.RequestRoomID(token, common.GameName)
	if err != nil {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "token 请求失败")
		return
	}

	roomInfo := douyin.RoomInfo{}

	if err := json.Unmarshal(result, &roomInfo); err != nil {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "json 解析失败")
		return
	}

	if roomInfo.ErrorCode != 0 {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "json 解析失败: "+roomInfo.ErrorMsg)
		return
	}

	collection := databases.MongoDB.Collection(common.GameName + models.AnchorCollection)
	filter := bson.M{"anchor_id": roomInfo.AnchorOpenId}
	exists, err := mongodb.DocumentExists(collection, filter)
	if err != nil {
		debug.Logf(debug.Error, fmt.Sprintf("判断失败: %v", err))
	} else if exists {
		debug.Logln(debug.Info, "该主播已存在")
	} else {
		anchor := models.AnchorInfoBasic{
			AnchorId:     roomInfo.AnchorOpenId,
			Score:        0,
			UnlockItemId: []uint{},
		}

		// 插入主播数据
		err = mongodb.InsertCollection(collection, anchor)
		if err != nil {
			debug.Logf(debug.Error, fmt.Sprintf("插入主播id: [%s] 失败, 原因: %+v", anchor.AnchorId, err))
			return
		}
	}

	tool.Resp(c.Writer, message.Success, roomInfo, "请求成功")
}

// 聊天弹幕消息 [post]
func OnLiveComment(c *gin.Context) {
	signature := c.Request.Header.Get("x-signature")
	if signature == "" {
		debug.Logln(debug.Info, "Comment 不是有效数据，直接返回====================")
		c.JSON(http.StatusOK, 200)
		return
	}
	/// 比对签名成功， 返回给客户端
	msg, err := CheckSignature(c)
	if err == nil {
		/// 这里暂时不转一遍， 直接 返回给客户端
		/// 后续如果有需要处理消息数据，在处理
		//data := make([]LiveComment, 0)
		//err := json.Unmarshal([]byte(msg.Body), &data)
		//
		//if err == nil {
		//	/// 返回给客户端
		//	fmt.Printf("消息处理完毕， 返回给客户端[roomId:%s][%s]\n", msg.RoomId, msg.Body)
		//	message.SendMsg(msg.RoomId, []byte(msg.Body))
		//}

		toClientLiveMsg := &ws.LiveInteractiveData{
			Message: message.Message{
				MsgType: message.SCLiveCommentMsg,
				RoomId:  msg.RoomId,
			},
			Data: msg.Body,
		}
		if ws.IsRoomID(msg.RoomId) {
			toClientLiveMsg.SendToClient(msg.RoomId)
		} else {
			reqBody, err := json.Marshal(&toClientLiveMsg)
			if err != nil {
				debug.Logln(debug.Error, "json 格式化失败:", err)
				return
			}
			debug.Logln(debug.Info, "[聊天消息] 没有找到此玩家的连接， 广播给其他服务器:", string(reqBody))
			net.BroadcastMessage("live-message", string(reqBody))
		}

	}

	c.JSON(http.StatusOK, 200)
}

// / 校验数据的合法性
func CheckSignature(c *gin.Context) (douyin.DanmuLiveData, error) {

	/// 签名用的随机字符串
	nonceStr := c.Request.Header.Get("x-nonce-str")
	/// 发送消息的毫秒级时间戳
	timestamp := c.Request.Header.Get("x-timestamp")
	/// 请求签名，业务方接收后需要计算和校验签名，防伪造和篡改
	signature := c.Request.Header.Get("x-signature")
	/// 房间id
	roomid := c.Request.Header.Get("x-roomid")
	/// 消息类型
	msgtype := c.Request.Header.Get("x-msg-type")

	headers := map[string]string{
		"x-nonce-str": nonceStr,
		"x-timestamp": timestamp,
		"x-roomid":    roomid,
		"x-msg-type":  msgtype,
	}
	s, _ := ioutil.ReadAll(c.Request.Body) //把	body 内容读入字符串 s
	//utils.Println("从Http读取到原始body, ", string(s))

	//buf := new(bytes.Buffer)
	//buf.ReadFrom(c.Request.Body)
	body := string(s)
	secret := config.GetConfig("app").GetString("douyin.appSecret")

	for key, value := range headers {
		debug.Logln(debug.Debug, fmt.Sprintf("[%s : %s]", key, value))
	}
	//utils.Println("Request PostForm body : ", body)
	//utils.Println("appSecret : ", secret)

	bodyStr := string(s)
	tempSign := douyin.Signature(headers, bodyStr, secret)

	/// 比对签名
	if signature != tempSign {
		//utils.Println(fmt.Sprintf("[OnLiveComment][签名比对错误]:[signature=%s : tempSign=%s]", signature, tempSign))
	}

	debug.Logln(debug.Debug, "当前房间id：", roomid)
	data := douyin.DanmuLiveData{
		RoomId: roomid,
		Body:   body,
	}

	return data, nil
}

// 礼物弹幕消息 [post]
func OnLiveGift(c *gin.Context) {
	signature := c.Request.Header.Get("x-signature")
	if signature == "" {
		debug.Logln(debug.Info, "Gift 不是有效数据，直接返回====================")
		c.JSON(http.StatusOK, 200)
		return
	}
	/// 比对签名成功， 返回给客户端
	msg, err := CheckSignature(c)
	if err == nil {
		/// 这里暂时不转一遍， 直接 返回给客户端
		/// 后续如果有需要处理消息数据，在处理
		data := make([]models.LiveGift, 0)
		err := json.Unmarshal([]byte(msg.Body), &data)
		if err == nil {
			/// 返回给客户端
			for _, gift := range data {
				game_service.AddGiftScore(common.GameName, msg.RoomId, uint64(gift.GiftNum)*uint64(gift.GiftValue))
			}
		}

		toClientLiveMsg := &ws.LiveInteractiveData{
			Message: message.Message{
				MsgType: message.SCLiveGiftMsg,
				RoomId:  msg.RoomId,
			},
			Data: msg.Body,
		}
		if ws.IsRoomID(msg.RoomId) {
			toClientLiveMsg.SendToClient(msg.RoomId)
		} else {
			reqBody, err := json.Marshal(toClientLiveMsg)
			if err != nil {
				debug.Logln(debug.Error, "json 格式化失败:", err)
				return
			}
			debug.Logln(debug.Info, "[礼物消息]没有找到此玩家的连接， 广播给其他服务器:", string(reqBody))
			net.BroadcastMessage("live-message", string(reqBody))
		}
	}

	c.JSON(http.StatusOK, 200)
}

// 点赞弹幕消息 [post]
func OnLiveLike(c *gin.Context) {
	signature := c.Request.Header.Get("x-signature")
	if signature == "" {
		debug.Logln(debug.Warn, "like，直接返回====================")
		c.JSON(http.StatusOK, 200)
		return
	}
	/// 比对签名成功， 返回给客户端
	msg, err := CheckSignature(c)
	if err == nil {
		/// 这里暂时不转一遍， 直接 返回给客户端
		/// 后续如果有需要处理消息数据，在处理
		//data := make([]LiveLike, 0)
		//err := json.Unmarshal([]byte(msg.Body), &data)
		//
		//if err == nil {
		//	/// 返回给客户端
		//	fmt.Printf("消息处理完毕， 返回给客户端[roomId:%s][%s]\n", msg.RoomId, msg.Body)
		//	message.SendMsg(msg.RoomId, []byte(msg.Body))
		//}
		toClientLiveMsg := &ws.LiveInteractiveData{
			Message: message.Message{
				MsgType: message.SCLiveLikeMsg,
				RoomId:  msg.RoomId,
			},
			Data: msg.Body,
		}

		if ws.IsRoomID(msg.RoomId) {
			toClientLiveMsg.SendToClient(msg.RoomId)
		} else {
			reqBody, err := json.Marshal(toClientLiveMsg)
			if err != nil {
				debug.Logln(debug.Error, "json 格式化失败:", err)
				return
			}
			debug.Logln(debug.Info, "[礼物消息]没有找到此玩家的连接， 广播给其他服务器:", string(reqBody))
			net.BroadcastMessage("live-message", string(reqBody))
		}
	}

	c.JSON(http.StatusOK, 200)
}

var mutex sync.Mutex

// 更新当前排行榜信息
func SyncRankData(c *gin.Context) {
	roomId := c.Query("roomId")

	fmt.Println("房间id：", roomId)
	// if roomId == "" {
	// 	//utils.Resp(c.Writer, ms.ErrorMsg, nil, "房间id错误, 请重新启动玩法")
	// 	return
	// }
	// ok := message.IsRoomID(roomId)
	// if !ok {
	// 	//utils.Resp(c.Writer, ms.ErrorMsg, nil, "房间id")
	// 	return
	// }

	var users []models.UserRankBasic
	if err := c.ShouldBindJSON(&users); err != nil {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "json 解析失败")
		return
	}
	mutex.Lock()
	defer mutex.Unlock()

	/// 更新当前排行数据进入数据库
	for _, player := range users {
		/// 先获取当前的能量值
		energyValue, err := rank.GetPlayerRankDataFromRedis(databases.Rediss, player.PlayerId)
		if err != nil {
			debug.Logln(debug.Error, err)
			debug.Logf(debug.Warn, "没有缓存排行数据， 直接更新到redis")
		} else {
			player.Energy += uint64(energyValue)
			debug.Logf(debug.Debug, fmt.Sprintf("当前能量值：%f, 叠加后能量值：%d", energyValue, player.Energy))
		}

		err = rank.UpdateEnergyInRedis(databases.Rediss, &player)
		if err != nil {
			debug.Logf(debug.Error, fmt.Sprintf("更新玩家数据到redis失败， playerId:%s, playerName:%s, error:%s", player.PlayerId, player.PlayerName, err))
			continue
		}
	}

	var playerRanks []models.UserRankBasic
	players, err := rank.GetTopTenRank(databases.Rediss, int64(100))
	if err != nil {
		debug.Logln(debug.Error, "获取排行榜前十名玩家错误, error:", err)
		tool.Resp(c.Writer, message.ErrorMsg, playerRanks, "获取前十名玩家失败")
		return
	}

	tool.Resp(c.Writer, message.Success, players, "更新排行榜数据成功")
}

func GetPlayerRankNumber(c *gin.Context) {
	roomId := c.Query("roomId")
	playerId := c.Query("playerId")
	//gameName := c.Query("gameName")

	debug.Logf(debug.Debug, fmt.Sprintf("获取排行榜玩家的排名， roomId=%s, playerId=%s", roomId, playerId))
	// if roomId == "" {
	// 	return
	// }
	// if !message.IsRoomID(roomId) {
	// 	//utils.Resp(c.Writer, ms.ErrorMsg, nil, "该房间不存在")
	// 	return
	// }
	// if playerId == "" {
	// 	return
	// }

	rankNumber, err := rank.GetPlayerRankNum(databases.Rediss, playerId)
	if err != nil {
		tool.Resp(c.Writer, message.Success, 9999, "查找当前玩家失败")
		return
	}

	tool.Resp(c.Writer, message.Success, rankNumber, fmt.Sprintf("当前玩家排名：%s", rankNumber))
}

// / 上报用户阵营数据
func UploadUserGroupInfo(c *gin.Context) {
	RoomId := c.Query("room_id")
	RoundId := c.Query("round_id")
	OpenId := c.Query("open_id")
	GroupId := c.Query("group_id")

	if RoomId == "" {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "房间不存在")
		return
	}
	if !ws.IsRoomID(RoomId) {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "直播间未启动")
		return
	}
	if OpenId == "" {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "用户不存在")
		return
	}

	var users models.UserInfoBasic
	if err := c.ShouldBindJSON(&users); err != nil {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "json 解析失败")
		return
	}
	mutex.Lock()
	defer mutex.Unlock()

	err := rank.UpdateUserInfoInRedis(databases.Rediss, &users)
	if err != nil {
		debug.Logf(debug.Error, fmt.Sprintf("更新玩家数据到redis失败， playerId:%s, playerName:%s, error:%s", users.PlayerId, users.NickName, err))
		return
	}

	rank.UploadUserGroupInfo(RoundId, OpenId, RoomId, GroupId)

	tool.Resp(c.Writer, message.Success, nil, "上报用户数据成功")
}

/*
*
上传游戏对局数据
*/
func UploadGameUserInfo(c *gin.Context) {
	anchorOpenId := c.Query("anchorOpenId")
	roomId := c.Query("roomId")
	roundId, _ := strconv.ParseInt(c.Query("roundId"), 10, 64)
	uploadList := c.Query("uploadList")
	complete, _ := strconv.ParseBool(c.Query("complete"))

	debug.Logf(debug.Debug, "接收到上传数据: anchorId: [%s], roomId: [%s], roundId: [%s]", anchorOpenId, roomId, roundId)

	if anchorOpenId == "" {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "主播id错误")
		return
	}
	if roomId == "" {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "房间id错误")
		return
	}
	if !ws.IsRoomID(roomId) {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "该房间不存在")
		return
	}

	var users []models.UploadUserData
	if err := c.ShouldBindJSON(&users); err != nil {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "json 解析失败")
		return
	}

	rank.UploadGameRoundInfo(anchorOpenId, roomId, roundId, users, complete)

	if uploadList == "1" {
		rank.UploadGameRankList(anchorOpenId, roomId, roundId, users)
	}

	tool.Resp(c.Writer, message.Success, nil, "上报排行榜成功")
}

/** 完成对局信息 */
func CompleteUploadUserResult(c *gin.Context) {
	anchorOpenId := c.Query("anchorOpenId")
	roomId := c.Query("roomId")
	roundId, _ := strconv.ParseInt(c.Query("roundId"), 10, 64)

	if anchorOpenId == "" {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "主播id错误")
		return
	}
	if roomId == "" {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "房间id错误")
		return
	}
	if !ws.IsRoomID(roomId) {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "该房间不存在")
		return
	}

	rank.CompleteUploadUserResult(anchorOpenId, roomId, roundId)

	tool.Resp(c.Writer, message.Success, nil, "完成上传")
}

// 记录游戏排行榜信息
func SyncUserBasicRank(c *gin.Context) {
	roomId := c.Query("roomId")

	fmt.Println("同步玩家数据，房间id：", roomId)

	if roomId == "majixiong" {
		debug.Logln(debug.Debug, "测试房间id， 直接跳过检测", roomId)
	} else {
		if roomId == "" {
			tool.Resp(c.Writer, message.ErrorMsg, nil, "房间id错误, 请重新启动玩法")
			return
		}
		if !ws.IsRoomID(roomId) {
			tool.Resp(c.Writer, message.ErrorMsg, nil, "该房间不存在")
			return
		}
	}

	var users []models.UserRankBasic
	if err := c.ShouldBindJSON(&users); err != nil {
		tool.Resp(c.Writer, message.ErrorMsg, nil, "json 解析失败")
		return
	}

	/// 更新玩家数据
	rank.SaveUsersToMongoAndRedis(databases.Rediss, databases.MongDBClient, users)

	for _, player := range users {
		rankValue, err := rank.GetPlayerRankNum(databases.Rediss, player.PlayerId)
		if err != nil {
			debug.Logf(debug.Debug, fmt.Sprintf("获取: {%s} 排名错误", player.PlayerId))
			continue
		}
		player.RankNumber = uint(rankValue)
		debug.Logf(debug.Debug, fmt.Sprintf("更新玩家排名 playerId: [%s], rank：[%d]", player.PlayerId, player.RankNumber))
	}

	tool.Resp(c.Writer, message.Success, users, "更新成功")
}
